#pragma once

#include "slre.h"
#include "SimpleList.hpp"

typedef void(*OPACITYCHANGEDFN)(bool);

class OpacityUtils abstract sealed
{
public:
	static void SetOpacityChangedCallback(OPACITYCHANGEDFN pfnOpacityChangedCallback)
	{
		m_opacityChangedCallback = pfnOpacityChangedCallback;
	}

	static HRESULT RestoreOpacity()
	{
		FindTaskbars();
		if (m_isOpacityEnabled)
		{
			return ChangeOpacity(m_isOpacityEnabled);
		}
		return S_OK;
	}

	static HRESULT ChangeOpacity(bool isEnabled)
	{
		if (0 == m_taskbars.Count)
		{
			m_isOpacityEnabled = !isEnabled;
			return -1;
		}

		DWM_BLURBEHIND blurBehind;
		SecureZeroMemory(&blurBehind, sizeof(blurBehind));
		blurBehind.dwFlags = DWM_BB_ENABLE;
		blurBehind.fEnable = isEnabled ? TRUE : FALSE;

		for (int i = 0; i < m_taskbars.Count; i++)
		{
			DwmEnableBlurBehindWindow(m_taskbars[i], &blurBehind);
		}

		m_isOpacityEnabled = isEnabled;
		m_opacityChangedCallback(isEnabled);
		return 0;
	}

	static void FindTaskbars()
	{
		m_taskbars.Clear();
		EnumWindows(&FindTaskbarCallback, NULL);
	}

	static BOOL CALLBACK FindTaskbarCallback(HWND hWnd, LPARAM lParam)
	{
		char className[0x100];
		GetClassNameA(hWnd, className, 0x100);

		int match = slre_match("(?i)Shell_.*TrayWnd", className, strlen(className), NULL, 0);
		if (match >= 0)
		{
			m_taskbars.Add(hWnd);
		}

		return TRUE;
	}

private:
	static SimpleList<HWND> m_taskbars;
	static bool m_isOpacityEnabled;
	static OPACITYCHANGEDFN m_opacityChangedCallback;
};

__declspec(selectany) SimpleList<HWND> OpacityUtils::m_taskbars;
__declspec(selectany) bool OpacityUtils::m_isOpacityEnabled;
__declspec(selectany) OPACITYCHANGEDFN OpacityUtils::m_opacityChangedCallback;
